﻿namespace Ex04.Menus.Delegates
{
    using System;
    using System.Collections.Generic;
    using System.Text;

    /// <summary>
    /// TODO: Update summary.
    /// </summary>
    public class Menu : ISelector
    {
        #region Messages
        private const char k_TitleLineChar = '-';
        private const string k_MenuItemFormat = "{0}. {1}";
        private const string k_ChooseOption = "Please choose an option: ";
        private const string k_ErrorOutOfLimitFormat = "Please choose only allowed option ({0} - {1}).";
        private const string k_ErrorWrongType = "Only numbers are allowed. Please try again";
        private const string k_PressAnyKey = "Press any key to continue...";
        #endregion

        #region Consts
        private const int k_MenuStartingCount = 0;
        #endregion

        #region Data Members
        private readonly string r_Title;
        private readonly List<ISelector> r_MenuSelections;
        #endregion

        #region Constructors
        public Menu(string i_Title, string i_TitleOfBack)
        {
            r_Title = i_Title;
            r_MenuSelections = new List<ISelector>();
            MenuItem exitMenu = new MenuItem(i_TitleOfBack);
            r_MenuSelections.Add(exitMenu);
        }
        #endregion

        #region Public Methods
        public void AddMenu(ISelector i_Menu)
        {
            r_MenuSelections.Add(i_Menu);
        }

        public void RemoveMenu(ISelector i_Menu)
        {
            r_MenuSelections.Remove(i_Menu);
        }

        public void onSelect()
        {
            WaitForUserChoice();
        }

        public void ExecuteAction()
        {
            Show();
        }

        public override string ToString()
        {
            return r_Title;
        }
        #endregion

        #region Private Methods
        private void Show()
        {
            StringBuilder output = new StringBuilder();
            uint indexOfMenuItems = k_MenuStartingCount;

            Console.Clear();
            output.AppendLine(r_Title);
            output.AppendLine(new string(k_TitleLineChar, r_Title.Length));

            foreach (ISelector menuSelection in r_MenuSelections)
            {
                output.AppendLine(string.Format(k_MenuItemFormat, indexOfMenuItems, menuSelection.ToString()));
                ++indexOfMenuItems;
            }

            output.AppendLine(k_ChooseOption);
            Console.Write(output);
        }

        private void WaitForUserChoice()
        {
            bool closeMenu = false;
            bool goodInput = false;
            int optionChosen = -1;

            do
            {
                ExecuteAction();
                goodInput = int.TryParse(Console.ReadLine(), out optionChosen);

                if (goodInput)
                {
                    if (isLegitMenuChoice(optionChosen))
                    {
                        r_MenuSelections[optionChosen].onSelect();
                        if (optionChosen.Equals(k_MenuStartingCount))
                        {
                            closeMenu = true;
                        }
                    }
                    else
                    {
                        Console.WriteLine(string.Format(k_ErrorOutOfLimitFormat, k_MenuStartingCount, r_MenuSelections.Count + k_MenuStartingCount - 1));
                        pressAnyKey();
                    }
                }
                else
                {
                    Console.WriteLine(k_ErrorWrongType);
                    pressAnyKey();
                }
            } 
            while (!closeMenu);
        }

        private bool isLegitMenuChoice(int i_MenuChoice)
        {
            return i_MenuChoice < (r_MenuSelections.Count + k_MenuStartingCount) && i_MenuChoice >= k_MenuStartingCount;
        }
        #endregion

        #region Internal Methods
        internal static void pressAnyKey()
        {
            Console.WriteLine(k_PressAnyKey);
            Console.ReadKey();
        }
        #endregion
    }
}
